package sketch.specs;

import java.io.File;
import java.io.IOException;
import java.util.List;

import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.TypeDeclaration;

import sketch.ast.ASTUtils;
import sketch.util.Globals;

import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;

public class TreeMapSketchingTest extends TestCase {
	
	public static Test suite() {
		return new TestSuite(TreeMapSketchingTest.class);
	}
	
	//some field used for testing
	String sketchFilePath = "./testfiles/sketch/specs/TreeMapSketch.java"; 
	String outputPath = "./testfiles/autogen/";
	String packageName = "autogen";
	//without removing
	String dumpedClassName = "TreeMapRemoveExpand_Auto_Gen";
	
	//after replacing the symbolic values
	String dumpedClassNameWithSymValueReplaced = "TreeMapRemoveExpand_Sym_Removed_Auto_Gen";
	
	//expand the ICSE'11 NIER paper example, and dump to a file
	public void testExpandTreeMapsSketch() throws IOException {
		SketchedMethodsCreator creator = new SketchedMethodsCreator(sketchFilePath);
		List<SketchedMethodDeclaration> sketchedMethods = creator.createSketchedMethodList();
		
		assertEquals(1, sketchedMethods.size());
		
		SketchedMethodDeclaration sketchMethod = sketchedMethods.get(0);
		System.out.println(sketchMethod);
		
		assertEquals(0, sketchMethod.numOfChildren());
		assertEquals(0, sketchMethod.numOfSubBlocks());
		
		assertEquals(1, sketchMethod.valueDeclarationStatements.size());
		
		//System.out.println(sketchMethod.valueDeclarationStatements.get(0));
		List<MethodDeclaration> results = sketchMethod.getMethodsAfterExpansion();
		assertEquals(340, results.size());
		
		StringBuilder sb = new StringBuilder();
		for(int i = 0; i < results.size(); i++) {
			MethodDeclaration method = results.get(i);
			
			MethodDumperAfterRemovingUnusedVars remover = new MethodDumperAfterRemovingUnusedVars(method);
			sb.append(remover.dumpMethodWithUnusedVarRemoved());
			sb.append(Globals.lineSep);
		}
		//dump to a file
//		System.out.println(sb.toString());
		StringBuilder output = this.wrapWithClassDeclaration(this.dumpedClassName, sb, true);
		
		randoop.util.Files.writeToFile(output.toString(), new File(outputPath + dumpedClassName + ".java"), false);
	}
	
	public void testRewriteSymbolicValue() throws IOException {
		String filePath = outputPath + dumpedClassName + ".java";
		//if the file does not exist, we need to call the previous test method before calling this
		if(!(new File(filePath).exists())) {
			this.testExpandTreeMapsSketch();
		}
		//replace the symbolic values
		List<MethodDeclaration> methods = ASTUtils.getAllMethods(ASTUtils.astRoot(filePath));
		assertEquals(340, methods.size());
		
		//remove each
		StringBuilder sb = new StringBuilder();
		
		SymbolicValueVisitor visitor = new SymbolicValueVisitor();
		for(MethodDeclaration method : methods) {
			method.accept(visitor);
			//visitor.getSymbolicMethodSignatures();
			sb.append(method.toString());
		}
		
		StringBuilder output = this.wrapWithClassDeclaration(this.dumpedClassNameWithSymValueReplaced, sb, false);
		
		randoop.util.Files.writeToFile(output.toString(), new File(outputPath + dumpedClassNameWithSymValueReplaced + ".java"));
	}
	
	public void testCreateJPFTestDriver() throws IOException {
		String filePath = outputPath + this.dumpedClassNameWithSymValueReplaced + ".java";
		if(!(new File(filePath).exists())) {
			this.testRewriteSymbolicValue();
		}
		CompilationUnit unit = ASTUtils.astRoot(filePath);
		
		assertTrue(unit.types().size() == 1);
		
		TypeDeclaration type = (TypeDeclaration)unit.types().get(0);
		
		List<MethodDeclaration> methods = ASTUtils.getAllMethods(unit);
		String[] methodsToCreate = new String[methods.size()];
		for(int i = 0; i < methodsToCreate.length; i++) {
			MethodDeclaration method_decl = methods.get(i);
			methodsToCreate[i] = method_decl.getName().getIdentifier();
		}
		WriteJPFSymbolicTestDriver.writeTestDriver(null, type, this.outputPath, methodsToCreate, this.packageName, new String[]{});
	}
	
	
	private StringBuilder wrapWithClassDeclaration(String className, StringBuilder content, boolean addOUnit) {
		StringBuilder output = new StringBuilder();
		
		output.append("package autogen;");
		output.append(Globals.lineSep);
		output.append(Globals.lineSep);
		if(addOUnit) {
		  output.append("import sketch.ounit.Values;");
		  output.append(Globals.lineSep);
		}
		output.append("import treemap.TreeMap;");
		output.append(Globals.lineSep);
		output.append("import junit.framework.TestCase;");
		output.append(Globals.lineSep);
		output.append(Globals.lineSep);
		
		output.append("public class " + className + " extends TestCase {");
		output.append(Globals.lineSep);
		output.append(content);
		output.append("}");
//		output.append("}")
		
		return output;
		
	}
}
